package com.spring.framework.beans.support;

import com.spring.framework.annotation.MyController;
import com.spring.framework.annotation.MyService;
import com.spring.framework.beans.config.MyBeanDefinition;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author ππ
 * @date 2020-11-16 17:00
 * @desc 声明配置文件解析器，将多种模板的文件解析，并封装成统一的配置文件类 BeanDefinition
 */

public class MyBeanDefinitionReader {
    /**保存配置文件*/
    private Properties config = new Properties();
    /**保存扫描的结果*/
    private List<String> registryBeanClasses = new ArrayList<>();
    public MyBeanDefinitionReader(String... configLocations) {
        //1、简单粗暴，只读取一个
        doLoadConfig(configLocations[0]);
        //2、扫描文件配置中的相关类
        doScanner(config.getProperty("scan-package"));
    }
    public List<MyBeanDefinition> loadBeanDefinitions() {
        if(this.registryBeanClasses.isEmpty()) {
            return null;
        }
        List<MyBeanDefinition> result = new ArrayList<>();
        try {
            for (String className : this.registryBeanClasses) {
                Class<?> clazz = Class.forName(className);
                if (clazz.isInterface()) {
                    continue;
                }
                // 处理beanName,有3种情况
                //1、自定义
                //2、默认首字母小写
                //3、接口采用全限定名
                String beanName = "";
                if (clazz.isAnnotationPresent(MyController.class)) {
                    beanName = clazz.getAnnotation(MyController.class).value().trim();
                } else if(clazz.isAnnotationPresent(MyService.class)) {
                    beanName = clazz.getAnnotation(MyService.class).value().trim();
                }
                // 如果为空，则默认首字母小写
                if("".equals(beanName)) {
                    beanName = toLowerCaseFirstLetter(clazz.getSimpleName());
                }
                result.add(doCreateBeanDefinition(beanName,className,clazz));
                for (Class i : clazz.getInterfaces()) {
                    result.add(doCreateBeanDefinition(i.getName(),clazz.getName(),clazz));
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    public Properties getConfig(){
        return this.config;
    }
    /**
     * 加载配置文件
     * @param configLocation
     */
    private void doLoadConfig(String configLocation) {
        // Spring源码中，对于classpath的处理，采用的策略
        // 这种写法，是1.7之后
        try(InputStream is = this.getClass().getClassLoader().getResourceAsStream(configLocation.replaceAll("classpath:",""))){
            config.load(is);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 扫描文件配置中的相关类，并存储到内存
     * @param scanPackage
     */
    private void doScanner(String scanPackage) {
        URL url = this.getClass().getClassLoader().getResource( scanPackage.replaceAll("\\.","/"));
        //不考虑报错的情况
        File parentFile = new File(url.getFile());
        for(File file : parentFile.listFiles()) {
            //如果是文件夹则进行递归
            if (file.isDirectory()) {
                doScanner(scanPackage + "." +file.getName());
            } else {
                // 只处理Class文件
                if (!file.getName().endsWith(".class")) {
                    continue;
                }
                registryBeanClasses.add(scanPackage + "." + file.getName().replace(".class",""));
            }
        }
    }

    /**
     * 构建BeanDefinition
     * @param beanName 实例bean名称
     * @param className 类的全限定名
     * @param clazz
     */
    private MyBeanDefinition doCreateBeanDefinition(String beanName, String className, Class<?> clazz) {
        MyBeanDefinition beanDefinition = new MyBeanDefinition();
        beanDefinition.setFactoryBeanName(beanName);
        beanDefinition.setBeanClassName(className);
        beanDefinition.setBeanClass(clazz);
        return beanDefinition;
    }
    /**
     * 首字母小写
     * @param simpleName
     * @return
     */
    private String toLowerCaseFirstLetter(String simpleName) {
        char[] chars = simpleName.toCharArray();
        chars[0]+=32;
        return new String(chars);
    }

}
